//
//  SHGCDViewController.m
//  SDemo
//
//  Created by gg on 2018/7/16.
//  Copyright © 2018年 gg. All rights reserved.
//

#import "SHGCDViewController.h"

@interface SHGCDViewController ()

@end

@implementation SHGCDViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title = @"GCD";
    self.view.backgroundColor = [UIColor whiteColor];
    [self initData];
    
}

-(void) initData {
    
    /**
     只需要告诉 GCD 想要如何执行什么任务，不需要编写任何线程管理代码。
     
     一些专业术语:
     dispatch :派遣/调度
     queue:队列
     用来存放任务的先进先出（FIFO）的容器
     sync:同步
     只是在当前线程中执行任务，不具备开启新线程的能力
     async:异步
     可以在新的线程中执行任务，具备开启新线程的能力
     concurrent:并发
     多个任务并发（同时）执行
     串行：
     一个任务执行完毕后，再执行下一个任务
     
     常用函数:
     
     GCD中的核心概念:
     1,任务
     
     // 1.用同步的方式执行任务
     dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
     
     // 2.用异步的方式执行任务
     dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
     
     // 在前面的任务执行结束后它才执行，而且它后面的任务等它执行完成之后才会执行
     dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
     
     2，队列
     串行队列： 一次只调度一个任务，一个任务完成后再调度下一个任务
     并发队列：并发队列可以同时调度多个任务，调度任务的方式，取决于执行任务的函数；并发功能只有在异步的（dispatch_async）函数下才有效；异步状态下，开启的线程上线由GCD底层决定
     
     自定义队列需要在mrc 状态下，使用dispatch_release 来释放
     
     */
    
    //死锁
    
//    NSLog(@"1");
//    dispatch_sync(dispatch_get_main_queue(), ^{
//        NSLog(@"2");
//    });
//    NSLog(@"3"); //输出的1
    
    
    dispatch_queue_t chuanqueue = dispatch_queue_create("chuan", NULL); //第二个参数 传递NULL或者DISPATCH_QUEUE_SERIAL 都是串行; 第一个参数 是对列名，该名称可以协助开发调试以及崩溃分析报告
    dispatch_queue_t mainqueue = dispatch_get_main_queue();//主队列用于UI以及触摸事件等的操作
    dispatch_queue_t bingqueue = dispatch_queue_create("bing", DISPATCH_QUEUE_CONCURRENT); //并
    
    //全局并发队列  dispatch_get_global_queue
    dispatch_queue_t globalqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //第一个参数有四个枚举
    
    /**
     //全局并发队列的优先级
     #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高优先级
     #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认（中）优先级
     //注意，自定义队列的优先级都是默认优先级
     #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低优先级
     #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台优先级
     
     
     备注： 全局并发队列与并发队列的区别：
     （1）全局并发队列与并发队列的调度方法相同
     （2）全局并发队列没有队列名称
     （3）在MRC开发中，全局并发队列不需要手动释放
     
     */
    
    
    
//    dispatch_async(globalqueue, ^{
//        //耗时间操作
//
//        dispatch_async(dispatch_get_main_queue(), ^{
//            //UI刷新
//        });
//    });
    
    /**
     执行任务的函数
     
     同步任务（注意：在主线程中，向主队列添加同步任务，会造成死锁。），异步任务（注意：当任务被添加到主队列后，会等待主线程空闲时才会调度该任务；添加到其他线程时，会开启新的线程调度任务。）
     
     */
    
//    for (int i = 0 ; i < 5; i ++) {
////        //异步任务,如果是在串行队列中依然是顺序输出
////        dispatch_async(chuanqueue, ^{
////            NSLog(@"%@ - %d",[NSThread currentThread],i);
////        });
//        dispatch_async(bingqueue, ^{
//            NSLog(@"%@ - %d",[NSThread currentThread],i);
//        });
//    }
    
    
    
    
    
    /**
     开发中如何选择队列：根据特点选择
     串行队列：对执行效率要求不高，对执行顺序要求高，性能消耗小
     并发队列：对执行效率要求高，对执行顺序要求不高，性能消耗大
     **** 如果不想兼顾 MRC 中队列的释放，建议选择使用全局队列 + 异步任务。如上面的例子****
     */
    
    //延时  dispatch_after
    
    //一次执行 如单例 dispatch_once_t
    
    /**
     
     调度组（队列组） dispatch_group_t
     //创建调度组
     dispatch_group_t group = dispatch_group_create();
     //将调度组添加到队列，执行 block 任务
     dispatch_group_async(group, queue, block);
     //当调度组中的所有任务执行结束后，获得通知，统一做后续操作
     dispatch_group_notify(group, dispatch_get_main_queue(), block);
     
     */
    
//    dispatch_group_t group = dispatch_group_create();
//    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
//        NSLog(@"第一个耗时操作");
//        NSLog(@"第二个耗时操作");
//        NSLog(@"第三个耗时操作");
//        NSLog(@"第四个耗时操作");
//
//    });
//
//    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
//        NSLog(@"第五个耗时操作");
//    });
//
//
//    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//        //两个操作结束后，回到主线程去；
//        NSLog(@"上面五个个操作结束后");
//    });
    
    //但是上面的操作在现实中并不会这样 因为网络请求需要时间，而线程的执行并不会等到请求完成才真正算完成，而是只是负责将请求发出去，想成就会认为自己的任务完成了。当三个请求都发送出去，就会执行notify中的内容，但请求结果返回的时间是不一定的，也就导致界面都刷新了，请求才返回，这就是无效的。同样使用 NSOperationQueue 添加依赖也会有上面的情况
    
    //要解决上面的问题，我们就要用到上面说的信号量来操作了。
    
    /**
     GCD信号量
     信号量是一个整数，在创建的时候会有一个初始值，这个初始值往往代表我要控制的同时操作的并发数。在操作中，对信号量会有两种操作：信号通知与等待。信号通知时，信号量会+1，等待时，如果信号量大于0，则会将信号量-1，否则，会等待直到信号量大于0。什么时候会大于零呢？往往是在之前某个操作结束后，我们发出信号通知，让信号量+1。
     
     计数为0时等待，计数为1或者大于1时，减去1而不等待。
     
     我们来看看GCD中的三个信号量操作：
     dispatch_semaphore_create：创建一个信号量（semaphore）
     dispatch_semaphore_signal：信号通知，即让信号量+1
     dispatch_semaphore_wait：等待，直到信号量大于0时，即可操作，同时将信号量-1

     */
    
//    dispatch_semaphore_t sem = dispatch_semaphore_create(3);
//    for (int i = 0; i < 100; i ++ ) {
//        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
//        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//            dispatch_semaphore_signal(sem);
//        });
//    }
    
    //上面代码表示我要操作100次，但是控制允许同时并发的操作最多只有5次，当并发量达到5后，信号量就减小到0了，这时候wait操作会起作用，DISPATCH_TIME_FOREVER表示会永远等待，一直等到信号量大于0，也就是有操作完成了，将信号量+1了，这时候才可以结束等待，进行操作，并且将信号量-1，这样新的任务又要等待。
    
//    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
//    [网络请求:{
//        成功：dispatch_semaphore_signal(sema);
//        失败：dispatch_semaphore_signal(sema);
//    }];
//    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    
    
    
//    dispatch_semaphore_t sem = dispatch_semaphore_create(1);
//    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//
//    dispatch_async(queue, ^{
//        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
//        NSLog(@"task 1");
//
//    });
//
//    dispatch_async(queue, ^{
//        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
//        NSLog(@"task 2");
//
//    });
//
//    dispatch_async(queue, ^{
//        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
//        NSLog(@"task 3");
//
//    });
    
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//    NSMutableArray *array = [[NSMutableArray alloc]init];
//    for (NSInteger i = 0; i < 100000; i++) {
//        dispatch_async(queue, ^{
//            /*
//             此时semaphore信号量的值如果 >= 1时：对semaphore计数进行减1,然后dispatch_semaphore_wait 函数返回。该函数所处线程就继续执行下面的语句。
//
//             此时semaphore信号量的值如果=0：那么就阻塞该函数所处的线程,阻塞时长为timeout指定的时间，如果阻塞时间内semaphore的值被dispatch_semaphore_signal函数加1了，该函数所处线程获得了信号量被唤醒。然后对semaphore计数进行减1并返回，继续向下执行。 如果阻塞时间内没有获取到信号量唤醒线程或者信号量的值一直为0，那么就要等到指定的阻塞时间后，该函数所处线程才继续向下执行。
//
//             执行到这里semaphore的值总是1
//             */
//            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//
//            /* 因为dispatch_semaphore_create创建的semaphore的初始值为1，执行完上面的
//             dispatch_semaphore_wait函数之后，semaphore计数值减1会变为0，所以可访问array对象的线程只有1个，因此可安全地对array进行操作。
//             */
//            [array addObject:[NSNumber numberWithInteger:i]];
//
//            /*
//             对array操作之后，通过dispatch_semaphore_signal将semaphore的计数值加1，此时semaphore的值由变成了1，所处
//             */
//            dispatch_semaphore_signal(semaphore);
//        });
//    }
    
    
    
    
// ***************************** 面试后的总结 **********************************************************
    
    //同步队列，只在当前线程中，异步队列，开辟过个线程
    dispatch_queue_t serielqueue =  dispatch_queue_create("label", DISPATCH_QUEUE_SERIAL); //串
    dispatch_queue_t conqueue = dispatch_queue_create("label2", DISPATCH_QUEUE_CONCURRENT); // 并
    dispatch_queue_t main_queue = dispatch_get_main_queue(); //主线程队列
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //全局并行队列
    
    //都是顺序输出
//    NSLog(@"1");
//    dispatch_sync(conqueue, ^{
//        NSLog(@"2");
//    });
//    NSLog(@"3");
//
//    NSLog(@"1");
//    dispatch_sync(serielqueue, ^{
//        NSLog(@"2");
//    });
//    NSLog(@"3");
    
    //[self syncSerial];
    //[self syncConcurrent];
    [self asyncSerial];
   // [self asyncConcurrent];
    
   // [self sh_barrier];
   // [self sh_groupNotify];
    //[self groupEnterAndLeave];
    
    
}

//串行队列 + 同步执行 (同步执行没有开启其他线程，串行输出)
-(void)syncSerial {
    
    /**
     输出结果:
     2018-07-31 13:56:11.436398+0800 SDemo[35328:1011556] currentThread---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:11.436596+0800 SDemo[35328:1011556] syncSerial---begin
     2018-07-31 13:56:13.437319+0800 SDemo[35328:1011556] 1---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:15.437697+0800 SDemo[35328:1011556] 1---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:17.451508+0800 SDemo[35328:1011556] 2---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:19.452951+0800 SDemo[35328:1011556] 2---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:21.454639+0800 SDemo[35328:1011556] 3---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:23.455832+0800 SDemo[35328:1011556] 3---<NSThread: 0x60000007ab00>{number = 1, name = main}
     2018-07-31 13:56:23.456245+0800 SDemo[35328:1011556] syncSerial---begin
     
     
     */
    
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"syncSerial---begin");
    
    dispatch_queue_t queue = dispatch_queue_create("label", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_sync(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_sync(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    NSLog(@"syncSerial---begin");
}
//同步执行 + 并行队列 (同步执行没有开启其他线程，串行输出)
-(void)syncConcurrent {
    
    /**
     输出结果：
     2018-07-31 14:02:43.677284+0800 SDemo[35438:1015959] currentThread---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:43.677431+0800 SDemo[35438:1015959] asyncSerial---begin
     2018-07-31 14:02:45.678727+0800 SDemo[35438:1015959] 1---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:47.679156+0800 SDemo[35438:1015959] 1---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:49.679605+0800 SDemo[35438:1015959] 2---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:51.680909+0800 SDemo[35438:1015959] 2---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:53.681299+0800 SDemo[35438:1015959] 3---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:55.681591+0800 SDemo[35438:1015959] 3---<NSThread: 0x60000006e780>{number = 1, name = main}
     2018-07-31 14:02:55.681782+0800 SDemo[35438:1015959] asyncSerial --- end
     
     */
    dispatch_queue_t queue = dispatch_queue_create("label2", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t globel_queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t main = dispatch_get_main_queue();
    
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"asyncSerial---begin");
    
//    dispatch_sync(queue, ^{
//        for (int i = 0; i < 2; i ++) {
//            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
//            NSLog(@"1---%@",[NSThread currentThread]);
//        }
//    });
//
//    dispatch_sync(queue, ^{
//        for (int i = 0; i < 2; i ++) {
//            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
//            NSLog(@"2---%@",[NSThread currentThread]);
//        }
//    });
//
//    dispatch_sync(queue, ^{
//        for (int i = 0; i < 2; i ++) {
//            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
//            NSLog(@"3---%@",[NSThread currentThread]);
//        }
//    });
    
    dispatch_sync(globel_queue, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);
        }
    });
    
    dispatch_sync(globel_queue, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);
        }
    });
    
    dispatch_sync(globel_queue, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncSerial --- end");
    
    NSLog(@"1");
    dispatch_sync(main, ^{
        NSLog(@"2"); //主线程同步，死锁崩溃
    });
    NSLog(@"3");
}
//串行队列 + 异步执行
-(void)asyncSerial{
    
    /**
     输出结果：注意和 同步串行 比较begin 和 end 的输出位置
     
     2018-07-31 14:17:28.701208+0800 SDemo[35819:1030741] currentThread---<NSThread: 0x60400006bb00>{number = 1, name = main}
     2018-07-31 14:17:28.701350+0800 SDemo[35819:1030741] asyncSerial---begin
     2018-07-31 14:17:28.701625+0800 SDemo[35819:1030741] asyncSerial---end
     2018-07-31 14:17:28.702123+0800 SDemo[35819:1030741] viewWillAppear: <SHGCDViewController: 0x7fd97ec20590>
     2018-07-31 14:17:30.702692+0800 SDemo[35819:1030865] 1 --- <NSThread: 0x6040004698c0>{number = 3, name = (null)}
     2018-07-31 14:17:32.707246+0800 SDemo[35819:1030865] 1 --- <NSThread: 0x6040004698c0>{number = 3, name = (null)}
     2018-07-31 14:17:34.709826+0800 SDemo[35819:1030865] 2 --- <NSThread: 0x6040004698c0>{number = 3, name = (null)}
     2018-07-31 14:17:36.713708+0800 SDemo[35819:1030865] 2 --- <NSThread: 0x6040004698c0>{number = 3, name = (null)}
     2018-07-31 14:17:38.715650+0800 SDemo[35819:1030865] 3 --- <NSThread: 0x6040004698c0>{number = 3, name = (null)}
     2018-07-31 14:17:40.717752+0800 SDemo[35819:1030865] 3 --- <NSThread: 0x6040004698c0>{number = 3, name = (null)}
     
     */
    
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"asyncSerial---begin");
    
    dispatch_queue_t queue = dispatch_queue_create("label3", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1 --- %@",[NSThread currentThread]);
        }
    });

    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2 --- %@",[NSThread currentThread]);
        }
    });

    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3 --- %@",[NSThread currentThread]);
        }
    });
    
    
//    //注意异步嵌套同步会造成死锁
//    dispatch_async(queue, ^{
//        for (int i = 0; i < 2; i++) {
//            [NSThread sleepForTimeInterval:2];
//            NSLog(@"1 --- %@",[NSThread currentThread]);
//        }
//        dispatch_sync(queue, ^{
//            for (int i = 0; i < 2; i++) {
//                [NSThread sleepForTimeInterval:2];
//                NSLog(@"2 --- %@",[NSThread currentThread]);
//            }
//        });
//    });
    
    NSLog(@"asyncSerial---end");
}

//异步执行，异步队列
-(void)asyncConcurrent {
    
    /**
     输出结果：
     2018-07-31 14:37:11.394930+0800 SDemo[36275:1049302] currentThread---<NSThread: 0x604000077ec0>{number = 1, name = main}
     2018-07-31 14:37:11.395475+0800 SDemo[36275:1049302] asyncConcurrent---begin
     2018-07-31 14:37:11.395636+0800 SDemo[36275:1049302] asyncConcurrent -- end
     2018-07-31 14:37:11.396006+0800 SDemo[36275:1049302] viewWillAppear: <SHGCDViewController: 0x7fd439402d00>
     2018-07-31 14:37:13.398915+0800 SDemo[36275:1049695] 2 --- <NSThread: 0x600000464700>{number = 5, name = (null)}
     2018-07-31 14:37:13.398915+0800 SDemo[36275:1049696] 3 --- <NSThread: 0x6000004647c0>{number = 3, name = (null)}
     2018-07-31 14:37:13.398915+0800 SDemo[36275:1049687] 1 --- <NSThread: 0x60400047d180>{number = 4, name = (null)}
     2018-07-31 14:37:15.402479+0800 SDemo[36275:1049696] 3 --- <NSThread: 0x6000004647c0>{number = 3, name = (null)}
     2018-07-31 14:37:15.402520+0800 SDemo[36275:1049687] 1 --- <NSThread: 0x60400047d180>{number = 4, name = (null)}
     2018-07-31 14:37:15.402533+0800 SDemo[36275:1049695] 2 --- <NSThread: 0x600000464700>{number = 5, name = (null)}
     */
    
    dispatch_queue_t queue = dispatch_queue_create("label5", DISPATCH_QUEUE_CONCURRENT);
    //dispatch_queue_t globel_queue = dispatch_get_global_queue(0, 0);
    
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"asyncConcurrent---begin");
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1 --- %@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2 --- %@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3 --- %@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncConcurrent -- end");
    
}

//线程间的通信
-(void)communication {
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t main = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        for (int i = 0; i < 0; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1 -- %@",[NSThread currentThread]);
        }
        
        //回到主线程刷新
        dispatch_async(main, ^{
            // 追加在主线程中执行的任务
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        });
    });
}

/**
 * 栅栏方法 dispatch_barrier_async
 */
-(void)sh_barrier {
    /**
     输出结果：
     2018-07-31 15:36:05.528131+0800 SDemo[37356:1095593] 1 -- <NSThread: 0x604000460680>{number = 3, name = (null)}
     2018-07-31 15:36:05.528210+0800 SDemo[37356:1095603] 2 -- <NSThread: 0x604000460f40>{number = 4, name = (null)}
     2018-07-31 15:36:07.532793+0800 SDemo[37356:1095603] 2 -- <NSThread: 0x604000460f40>{number = 4, name = (null)}
     2018-07-31 15:36:07.532839+0800 SDemo[37356:1095593] 1 -- <NSThread: 0x604000460680>{number = 3, name = (null)}
     2018-07-31 15:36:09.536021+0800 SDemo[37356:1095593] barrier -- <NSThread: 0x604000460680>{number = 3, name = (null)}
     2018-07-31 15:36:11.540289+0800 SDemo[37356:1095593] barrier -- <NSThread: 0x604000460680>{number = 3, name = (null)}
     2018-07-31 15:36:13.542532+0800 SDemo[37356:1095593] 4 -- <NSThread: 0x604000460680>{number = 3, name = (null)}
     2018-07-31 15:36:15.545879+0800 SDemo[37356:1095593] 4 -- <NSThread: 0x604000460680>{number = 3, name = (null)}
     */
    dispatch_queue_t queue1  =  dispatch_queue_create("com.inter.label", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue1, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1 -- %@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue1, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2 -- %@",[NSThread currentThread]);
        }
    });
    
    dispatch_barrier_async(queue1, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"barrier -- %@",[NSThread currentThread]);
        }

    });
    
    dispatch_async(queue1, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"4 -- %@",[NSThread currentThread]);
        }
    });
}

//组队列
-(void)sh_groupNotify {
    /**
     输出结果是：
     
     2018-07-31 15:59:38.547983+0800 SDemo[37785:1114408] currentThread---<NSThread: 0x60000007ed80>{number = 1, name = main}
     2018-07-31 15:59:38.548762+0800 SDemo[37785:1114408] group---begin
     2018-07-31 15:59:38.550018+0800 SDemo[37785:1114408] group---end
     2018-07-31 15:59:38.550425+0800 SDemo[37785:1114408] viewWillAppear: <SHGCDViewController: 0x7ff39552e230>
     2018-07-31 15:59:40.554392+0800 SDemo[37785:1115616] 3---<NSThread: 0x60400066c140>{number = 5, name = (null)}
     2018-07-31 15:59:40.554394+0800 SDemo[37785:1115615] 2---<NSThread: 0x60400066c440>{number = 4, name = (null)}
     2018-07-31 15:59:40.554411+0800 SDemo[37785:1115603] 1---<NSThread: 0x60400066c980>{number = 3, name = (null)}
     2018-07-31 15:59:42.555462+0800 SDemo[37785:1115616] 3---<NSThread: 0x60400066c140>{number = 5, name = (null)}
     2018-07-31 15:59:42.555462+0800 SDemo[37785:1115615] 2---<NSThread: 0x60400066c440>{number = 4, name = (null)}
     2018-07-31 15:59:42.555491+0800 SDemo[37785:1115603] 1---<NSThread: 0x60400066c980>{number = 3, name = (null)}
     2018-07-31 15:59:44.556083+0800 SDemo[37785:1114408] 4---<NSThread: 0x60000007ed80>{number = 1, name = main}
     2018-07-31 15:59:46.556422+0800 SDemo[37785:1114408] 4---<NSThread: 0x60000007ed80>{number = 1, name = main}
     
     */
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"group---begin");
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        //回到主线程刷新
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"4---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    NSLog(@"group---end");
}

/**
 * 队列组 dispatch_group_enter、dispatch_group_leave
 */
-(void) groupEnterAndLeave {
    
    /**
     输出结果如下：
     
     2018-07-31 16:04:03.894055+0800 SDemo[37939:1120026] group---begin
     2018-07-31 16:04:03.894619+0800 SDemo[37939:1120026] viewWillAppear: <SHGCDViewController: 0x7ffad071a0b0>
     2018-07-31 16:04:05.894814+0800 SDemo[37939:1120389] 2---<NSThread: 0x6040004672c0>{number = 4, name = (null)}
     2018-07-31 16:04:05.894815+0800 SDemo[37939:1120380] 1---<NSThread: 0x60000027e940>{number = 3, name = (null)}
     2018-07-31 16:04:07.896415+0800 SDemo[37939:1120389] 2---<NSThread: 0x6040004672c0>{number = 4, name = (null)}
     2018-07-31 16:04:07.896415+0800 SDemo[37939:1120380] 1---<NSThread: 0x60000027e940>{number = 3, name = (null)}
     2018-07-31 16:04:09.897012+0800 SDemo[37939:1120026] 3---<NSThread: 0x604000060900>{number = 1, name = main}
     2018-07-31 16:04:11.897426+0800 SDemo[37939:1120026] 3---<NSThread: 0x604000060900>{number = 1, name = main}
     2018-07-31 16:04:11.897591+0800 SDemo[37939:1120026] group---end
     */
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"group---begin");
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        // 追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        // 追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的异步操作都执行完毕后，回到主线程.
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
        }
        NSLog(@"group---end");
    });
    
    //    // 等待上面的任务全部完成后，会往下继续执行（会阻塞当前线程）
    //    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    //
    //    NSLog(@"group---end");
    
}

//如何让afn 实现同步请求
-(void)getSy {
//    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); //创建信号量
//    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//    [manager GET:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
//
//        dispatch_semaphore_signal(semaphore);//不管请求状态是什么，都得发送信号，否则会一直卡着进程
//    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//        dispatch_semaphore_signal(semaphore);//不管请求状态是什么，都得发送信号，否则会一直卡着进程
//    }];
//    
//    dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);  //等待
    

}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}



@end


